package com.jtemimal.utils;

import com.jtemimal.resp.CommandResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.exec.*;
import org.springframework.messaging.simp.SimpMessagingTemplate;

import java.io.*;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class InteractiveCommandExecutor {
    private static final Map<String, ExecuteStreamHandler> activeHandlers = new ConcurrentHashMap<>();
    private static final Map<String, DefaultExecutor> activeExecutors = new ConcurrentHashMap<>();
    private final SimpMessagingTemplate messagingTemplate;

    public InteractiveCommandExecutor(SimpMessagingTemplate messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }

    public CommandResult startCommand(String sessionId, String command) {
        try {
            // 创建命令行
            CommandLine cmdLine;
            if (System.getProperty("os.name").toLowerCase().contains("win")) {
                cmdLine = CommandLine.parse("cmd.exe");
                cmdLine.addArgument("/c");
                cmdLine.addArgument(command, false);
            } else {
                cmdLine = CommandLine.parse(command);
            }

            // 创建执行器
            DefaultExecutor executor = new DefaultExecutor();
            executor.setExitValues(null); // 允许任何退出值

            // 创建 PipedInputStream/PipedOutputStream 对来处理输入输出
            PipedOutputStream outputStream = new PipedOutputStream();
            PipedInputStream inputStream = new PipedInputStream(outputStream);
            ByteArrayOutputStream errorStream = new ByteArrayOutputStream();

            // 创建自定义的流处理器
            ExecuteStreamHandler streamHandler = new PumpStreamHandler(
                new OutputStreamCallback(sessionId),  // 标准输出
                new OutputStreamCallback(sessionId),  // 标准错误
                inputStream                          // 标准输入
            );

            executor.setStreamHandler(streamHandler);

            // 设置看门狗，防止进程无限运行
            ExecuteWatchdog watchdog = new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT);
            executor.setWatchdog(watchdog);

            // 存储处理器和执行器以供后续使用
            activeHandlers.put(sessionId, streamHandler);
            activeExecutors.put(sessionId, executor);

            // 在新线程中执行命令
            new Thread(() -> {
                try {
                    executor.execute(cmdLine);
                } catch (IOException e) {
                    log.error("Command execution error: {}", e.getMessage());
                    messagingTemplate.convertAndSend(
                        "/topic/interactive/" + sessionId,
                        new CommandResult(null, "Command execution error: " + e.getMessage())
                    );
                } finally {
                    terminateCommand(sessionId);
                }
            }).start();

            return CommandResult.interactive("Interactive session started.");
        } catch (IOException e) {
            log.error("Failed to start interactive command: {}", e.getMessage());
            return new CommandResult(null, "Failed to start command: " + e.getMessage());
        }
    }

    public void sendInput(String sessionId, String input) {
        ExecuteStreamHandler handler = activeHandlers.get(sessionId);
        if (handler instanceof PumpStreamHandler) {
            try {
                Field inputField = PumpStreamHandler.class.getDeclaredField("input");
                inputField.setAccessible(true);
                OutputStream out = (OutputStream) inputField.get(handler);
                out.write((input + "\n").getBytes());
                out.flush();
            } catch (IOException e) {
                log.error("Failed to send input: {}", e.getMessage());
            } catch (NoSuchFieldException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void terminateCommand(String sessionId) {
        DefaultExecutor executor = activeExecutors.remove(sessionId);
        if (executor != null && executor.getWatchdog() != null) {
            executor.getWatchdog().destroyProcess();
        }
        activeHandlers.remove(sessionId);
    }

    // 自定义输出流回调类
    private class OutputStreamCallback extends OutputStream {
        private final String sessionId;
        private final StringBuilder buffer = new StringBuilder();

        public OutputStreamCallback(String sessionId) {
            this.sessionId = sessionId;
        }

        @Override
        public void write(int b) throws IOException {
            char ch = (char) b;
            buffer.append(ch);
            
            // 当收到换行符时发送消息
            if (ch == '\n' || ch == '\r') {
                flush();
            }
        }

        @Override
        public void flush() throws IOException {
            if (buffer.length() > 0) {
                String output = buffer.toString();
                messagingTemplate.convertAndSend(
                    "/topic/interactive/" + sessionId,
                    CommandResult.interactive(output)
                );
                buffer.setLength(0);
            }
        }
    }
} 